import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import sk.upjs.gursky.bplustree.BPTree;

public class NeklastrovanyBPT {
	private BPTree<Kluc, NeklastrovanyZaznam> tree;
	private RandomAccessFile raf;
	private FileChannel channel;
	private ByteBuffer buffer;	
	
	private int countIOs;
	private Set<Long> longy = new HashSet<Long>();
	   
    public NeklastrovanyBPT() throws Exception{
        tree = new BPTree<Kluc, NeklastrovanyZaznam>(NeklastrovanyZaznam.class, new File("indexBPNeklastrovany.idx"));
        List<NeklastrovanyZaznam> zaznamy = new ArrayList<NeklastrovanyZaznam>();
       
        raf = new RandomAccessFile("clovek.tab", "r");
        channel = raf.getChannel();
        buffer = ByteBuffer.allocateDirect(4096);
       
        long dlzka = raf.length();
        long pocetStranok = dlzka / 4096;
       
        for (int i = 0; i < pocetStranok; i++) {
            buffer.rewind();
            channel.read(buffer);
            buffer.rewind();
            int pocetZaznamov = buffer.getInt();
           
            for (int j = 0; j < pocetZaznamov; j++) {
                Zaznam zaznam = new Zaznam();
                zaznam.load(buffer);
                
                NeklastrovanyZaznam neklastrovanyZaznam = new NeklastrovanyZaznam();
                neklastrovanyZaznam.setOffset(4096 * i + 4 + j * zaznam.getSize());
                neklastrovanyZaznam.setPriezvisko(zaznam.getPriezvisko());
                zaznamy.add(neklastrovanyZaznam);
//                System.out.println(neklastrovanyZaznam);
            }
           
        }
//        channel.close();
//        raf.close();
       
        Collections.sort(zaznamy);
        tree.openAndBatchUpdate(zaznamy.iterator(), zaznamy.size());
    }
   
    public List<Zaznam> rozsahovyDopyt(Kluc od, Kluc po) throws Exception {    	
    	countIOs = 0;
    	
    	List<NeklastrovanyZaznam> neklastrovaneZaznamy = tree.rozsahovyDopyt(od, po);
    	List<Zaznam> result = new ArrayList<Zaznam>(neklastrovaneZaznamy.size());
    	
    	for (NeklastrovanyZaznam neklastrovanyZaznam : neklastrovaneZaznamy) {
            buffer.rewind();
            long pageOffset = neklastrovanyZaznam.getOffset() % 4096;
            channel.read(buffer, neklastrovanyZaznam.getOffset() - pageOffset);
            
            longy.add(neklastrovanyZaznam.getOffset() - pageOffset);	//mnozina vsetkych offsetov stranok clovek.tabu - datovy subor
            
            buffer.rewind();
            buffer.position((int) pageOffset);
            Zaznam zaznam = new Zaznam();
            zaznam.load(buffer);
            result.add(zaznam);
            
            countIOs++;
		}
    	
    	return result;
    }
   
    public void close(){
        try {
            tree.close();
            channel.close();
            raf.close();
        } catch (IOException e){
            e.printStackTrace();
        }
    }
   
    public static void main(String[] args) throws Exception {
        NeklastrovanyBPT nkl = new NeklastrovanyBPT();
        
        nkl.tree.resetCountIOs();        
        long time = System.nanoTime();
        
        List<Zaznam> vysledok = nkl.rozsahovyDopyt(new Kluc("ayh"),new Kluc("99999999"));
        System.out.println(vysledok);
        time = System.nanoTime() - time;
        System.out.println(vysledok);
        System.out.println(time);
        
        System.out.println("Neklastrovany index - pocet I/O - indexovy subor: " + nkl.tree.getCountIOs());		//indexovy subor
        System.out.println("Neklastrovany index - pocet I/O - datovy subor: " + nkl.countIOs);					//datovy subor
        System.out.println(nkl.longy.size());
        nkl.close();       
    }   
}
